package com.zoran.study.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;


import java.util.Arrays;

/**
 * AppLog
 *
 * @author zouxm
 * @date 2018/4/11
 */
@Aspect
@Order(value = 1)
@Component
public class AppLog {

    //当 多个切面应用在一个连接点时候,order越小,优先级越高,优先执行,如果未指定order,多个切面之间顺序也是未知的

    //对于同一个切面来说,不同通知执行的顺序为 Around->Before->Method->Around->After->(AfterReturning || AfterThrowing)

    //对于同一个切面中同一类型的通知,执行顺序是随机的,如果一个切面定义了2个before通知到一个连接点
    @Pointcut("execution( * com.zoran.study.spring.service..*.*(..)) && !@annotation(MyAroud)")
    public static void pointcut() {
        //将切点定义为静态的 ,spring 可以进行缓存优化
    }

    @Before(value = "execution( * com.zoran.study.spring.service..*(..)) && !@annotation(MyAroud) && args(a,b,..)")
    public void before(int a, int b) {
        System.out.println("params:" + Arrays.asList(a, b)); //指定参数
        System.out.println("before invoke");
    }

    @After(value = "pointcut()")
    public void after() {
        System.out.println("after invoke");
    }

    @AfterReturning(pointcut = "pointcut()", returning = "result")
    public void after(JoinPoint jp, Object result) {
        System.out.println(jp.getSignature().getName());
        System.out.println(jp.getSignature().getDeclaringType());
        System.out.println(Arrays.toString(jp.getArgs()));
        System.out.println("返回值:" + result);
    }

    @AfterThrowing(pointcut = "pointcut()", throwing = "ex")
    public void afterThrow(JoinPoint jp, Throwable ex) {
        System.out.println(jp.getSignature().getName());
        System.out.println("exception:" + ex);
    }

    @Around(value = "@annotation(MyAroud)")
    public Object around(ProceedingJoinPoint jp) {
        System.out.println("before...");
        MethodSignature signature = (MethodSignature) jp.getSignature();
        System.out.println(signature.getMethod().getName());
        System.out.println(jp.getTarget()); //被代理的目标对象
//        System.out.println(jp.getThis());  //生成的代理对象
        try {
//            Object result = jp.proceed();
            Object[] args = jp.getArgs();
            if (args != null && args.length > 0 && args[0].getClass() == Integer.class) {
                //改变参数
                args[0] = 10;
            }
            Object result = jp.proceed(args);
            System.out.println("after..." + result);
            return result;
        } catch (Throwable throwable) {
            System.out.println("ex:" + throwable.getMessage());
        }
        return null;
    }
}
